# 基于simple模块的umqtt连接到点灯科技平台,要用robust模块，能自动重连
# 设备端publish时"todivice"要向手机app的Id号发布信息，手机端才能收到
from umqtt.robust import MQTTClient
from machine import RTC, reset
import time, ntptime, network
import json
import urequests

NTPHOST = 'ntp.aliyun.com'
KEEP_ALIVE_TIME = 120  # 设为120以内合理，我设为300就会掉线

wlan = network.WLAN(network.STA_IF)
rtc = RTC() 


class Device:      
    def __init__(self, subCallbackFunc = None):
        self.authKey = ""
        self.deviceName = ""
        self.password = ""
        self.uuid = ""
        self.set_callback = subCallbackFunc
        self.wifi_ssid = ""
        self.wifi_pwd = ""
        self.mqtt_client = None
        self.keepaliveTime = KEEP_ALIVE_TIME
        self.startTime = time.time()
        self.nowTime = time.time()
        self.ntpUpTime = time.ticks_ms()
        
    # 连接WiFi
    def connectWifi(self):                
        wlan.active(True)
        if wlan.isconnected():
            pass
        else:
            wlan.active(True)
            wlan.connect(self.wifi_ssid, self.wifi_pwd)
            print("\nWIFI is connecting...")        
            while (not wlan.isconnected()):
                 time.sleep_ms(50)            
        if wlan.status('rssi') >= 0:
            time.sleep(5)
            reset() # wifi信号错误，软复位
        print("\nWIFI connected.")
        print("Got IP: ", wlan.ifconfig()[0])
        return 0
        
    # 同步NTP时间
    def syncNtp(self):
        ntptime.host = NTPHOST
        while True:
            try:
                ntptime.settime()
                utc_time = ntptime.time()
                local_time = time.gmtime(utc_time + 28800) #东8区增加8*60*60秒
                rtc.datetime(local_time[0:3]+(local_time[6],)+local_time[3:6]+(0,))
                print("NTP synchro successful.")
                print("*" * 40)
                break
            except:
                print("NTP time out...")
                time.sleep(3)
        return 0
        
    # 连接MQTT服务器
    def connect(self):        
        # 获取broker连接参数请求网址
        url = 'https://iot.diandeng.tech/api/v1/user/device/diy/auth?authKey={0}'.format(self.authKey)
        response = urequests.get(url)
        data = response.text
        response.close()
        res = json.loads(data)
#         print(res)
        if res.get("message") == 1000:
            self.deviceName = res.get("detail").get("deviceName")
            username = res.get("detail").get("iotId")
            self.password = res.get("detail").get("iotToken")
            self.uuid = res.get("detail").get("uuid")
            self.topic_s = '/device/{0}/s'.format(self.deviceName)
            self.topic_r = '/device/{0}/r'.format(self.deviceName)
            print("password=", self.password)
            print("clientId=", self.deviceName)
            print("username=", username)
            print("topic_s=", self.topic_s)        
            print("topic_r=", self.topic_r)
            self.mqtt_client = MQTTClient(client_id = self.deviceName,
                server = "broker.diandeng.tech",
                user = username,
                password = self.password,
                keepalive = self.keepaliveTime
                )
            self.mqtt_client.set_callback(self.set_callback)
        else:
            return -1
        if self.mqtt_client.connect(True) == 0:
            print("MQTT broker connected.")
            print("*" * 40)
            print(" ")
            self.mqtt_client.subscribe(self.topic_r)
            self.startTime = time.time()
            self.ntpUpTime = time.ticks_ms()
            return 0
        else:
            return -2

    def reconnect(self):
        # WiFi重连
        self.connectWifi()        
        # 同步NTP时间     
        self.syncNtp()        
        # 连接MQTT服务器
        return self.connect()
    
    @property
    def isconnect(self):
        return self.mqtt_client.isconnect()

    def disconnect(self):
        if self.mqtt_client.isconnect():
            self.mqtt_client.disconnect()
    
    def begin(self, authKey = "", ssid = "", pwd = ""):       
        self.authKey = authKey
        self.wifi_ssid = ssid
        self.wifi_pwd = pwd
        
        # 连接WiFi
        self.connectWifi()
        
        # 同步NTP时间     
        self.syncNtp()
        
        # 连接MQTT服务器
        return self.connect()

    def checkData(self):
        self.mqtt_client.check_msg() # 非阻塞查询mqtt信息
        self.nowTime = time.time()
        if (self.nowTime - self.startTime) >= self.keepaliveTime:   
            self.mqtt_client.ping()
            self.startTime = self.nowTime #更新mqtt ping起始时间
            print("Ping MQTT broker.")
        if time.ticks_diff(time.ticks_ms(), self.ntpUpTime) > 3000000:
            self.ntpUpTime = time.ticks_ms()
            # 同步NTP时间     
            self.syncNtp()
    
    def checkAutoFormat(self):
        pass

    def send(self, message):
        self.startTime = time.time() #更新mqtt ping起始时间
        pub_data = {"toDevice": self.uuid, "data": {}}
        pub_data["data"].update(message)
        pub_str = json.dumps(pub_data)
        self.mqtt_client.publish(self.topic_s.encode(), pub_str.encode())
        
    def dataStore(self, data_dict):
        dt = 946684800-28800 # 与1970年1月1日0时0分0秒的时间戳差额，要减去+8时区差
        timeStamp = time.time() + dt
        
        # 时间序列数据保存http请求网址        
        url = "https://iot.diandeng.tech/api/v1/device/storage/ts"
        
        # 创建新的字典用于存储处理后的数据
        send_dict = {}
        # 遍历原始字典的键值对
        for key, value in data_dict.items():
            # 创建包含时间戳和数据的列表
            data_list = [[timeStamp, value]]
            # 将处理后的数据添加到新字典中
            send_dict[key] = data_list        
        request_data = {
            "device": self.deviceName,
            "token": self.password,
            "data": send_dict
        }
        # http请求方式
        try :
            result = urequests.post(url, json = request_data)
        except Exception as err:
            print("发生异常:", err)
            return
        response_data = result.json()
        if response_data["message"] == 1000:
            print("Data store ok at: ",timeStamp)
        else:
            print("Data store error, error message is {0}".format(response_data["detail"]))

    def run(self):
        if self.mqtt_client.isconnect() == 0:
            time.sleep_ms(5)
            self.reconnect()
        elif self.mqtt_client.isconnect() == 1:            
            self.checkData()
        elif self.mqtt_client.isconnect() > 1:
            self.mqtt_client.subscribe(self.topic_r) # 重新订阅主题
            self.mqtt_client.setState(1) # 状态设置为1，已连接
            with open("log.txt", 'a') as log:
                current_time=time.localtime()[:6]
                formatted_time = '{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}'.format(
                                current_time[0], current_time[1], current_time[2],
                                current_time[3], current_time[4], current_time[5])
                log.write("re_subscribe. #{0}\n".format(formatted_time))

    @property
    def wifiRssi(self):
        return wlan.status('rssi')